package com.mkx.core.monitor;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Redis分布式锁统计工具类
 * 用于收集和展示锁的执行性能指标
 */
public class RedisLockStats {

    private static final RedisLockStats INSTANCE = new RedisLockStats();
    private final ReentrantReadWriteLock statsLock = new ReentrantReadWriteLock();
    
    // 基础统计数据
    private final LongAdder totalAcquireCount = new LongAdder();
    private final LongAdder successAcquireCount = new LongAdder();
    private final LongAdder failedAcquireCount = new LongAdder();
    private final LongAdder totalReleaseCount = new LongAdder();
    private final LongAdder successReleaseCount = new LongAdder();
    private final LongAdder failedReleaseCount = new LongAdder();
    private final AtomicLong totalAcquireTime = new AtomicLong(0);
    private final AtomicLong maxAcquireTime = new AtomicLong(0);
    private final AtomicLong minAcquireTime = new AtomicLong(Long.MAX_VALUE);
    private final AtomicLong currentLockCount = new AtomicLong(0);
    private final AtomicLong peakLockCount = new AtomicLong(0);
    
    // 锁竞争监控相关统计
    private final LongAdder competitionCount = new LongAdder(); // 竞争次数（获取锁失败的重试次数）
    private final LongAdder highCompetitionCount = new LongAdder(); // 高竞争次数（重试超过阈值的情况）
    private final AtomicLong totalWaitTime = new AtomicLong(0); // 总等待时间（重试间隔总和）
    private final AtomicLong maxWaitTime = new AtomicLong(0); // 最大等待时间
    private final AtomicInteger concurrentContenders = new AtomicInteger(0); // 当前竞争锁的线程数
    private final AtomicInteger peakConcurrentContenders = new AtomicInteger(0); // 峰值竞争线程数

    private RedisLockStats() {
        // 私有构造函数，防止外部实例化
    }

    /**
     * 获取统计实例
     */
    public static RedisLockStats getInstance() {
        return INSTANCE;
    }

    /**
     * 记录锁获取开始
     */
    public void recordAcquireStart() {
        totalAcquireCount.increment();
    }

    /**
     * 记录锁获取成功
     * @param acquireTime 锁获取耗时
     */
    public void recordAcquireSuccess(long acquireTime) {
        successAcquireCount.increment();
        totalAcquireTime.addAndGet(acquireTime);
        
        // 更新最大和最小获取时间
        updateMaxMinTime(acquireTime);
        
        // 更新当前和峰值锁数量
        long current = currentLockCount.incrementAndGet();
        if (current > peakLockCount.get()) {
            peakLockCount.compareAndSet(peakLockCount.get(), current);
        }
    }

    /**
     * 记录锁获取失败
     */
    public void recordAcquireFailed() {
        failedAcquireCount.increment();
    }
    
    /**
     * 记录锁竞争事件
     * @param retryCount 当前重试次数
     * @param waitTime 本次等待时间
     */
    public void recordCompetition(int retryCount, long waitTime) {
        competitionCount.increment();
        
        // 记录总等待时间
        totalWaitTime.addAndGet(waitTime);
        
        // 更新最大等待时间
        long currentMax;
        do {
            currentMax = maxWaitTime.get();
            if (waitTime <= currentMax) {
                break;
            }
        } while (!maxWaitTime.compareAndSet(currentMax, waitTime));
        
        // 记录高竞争情况（重试超过3次）
        if (retryCount > 3) {
            highCompetitionCount.increment();
        }
    }
    
    /**
     * 记录锁竞争开始
     */
    public void recordContenderStart() {
        int current = concurrentContenders.incrementAndGet();
        // 更新峰值竞争线程数
        int peak;
        do {
            peak = peakConcurrentContenders.get();
            if (current <= peak) {
                break;
            }
        } while (!peakConcurrentContenders.compareAndSet(peak, current));
    }
    
    /**
     * 记录锁竞争结束
     */
    public void recordContenderEnd() {
        concurrentContenders.decrementAndGet();
    }

    /**
     * 记录锁释放开始
     */
    public void recordReleaseStart() {
        totalReleaseCount.increment();
    }

    /**
     * 记录锁释放成功
     */
    public void recordReleaseSuccess() {
        successReleaseCount.increment();
        currentLockCount.decrementAndGet();
    }

    /**
     * 记录锁释放失败
     */
    public void recordReleaseFailed() {
        failedReleaseCount.increment();
    }

    /**
     * 更新最大和最小获取时间
     */
    private void updateMaxMinTime(long acquireTime) {
        long currentMax;
        do {
            currentMax = maxAcquireTime.get();
            if (acquireTime <= currentMax) {
                break;
            }
        } while (!maxAcquireTime.compareAndSet(currentMax, acquireTime));

        long currentMin;
        do {
            currentMin = minAcquireTime.get();
            if (acquireTime >= currentMin) {
                break;
            }
        } while (!minAcquireTime.compareAndSet(currentMin, acquireTime));
    }

    /**
     * 获取统计信息
     */
    public StatsInfo getStatsInfo() {
        statsLock.readLock().lock();
        try {
            return new StatsInfo(
                    totalAcquireCount.sum(),
                    successAcquireCount.sum(),
                    failedAcquireCount.sum(),
                    totalReleaseCount.sum(),
                    successReleaseCount.sum(),
                    failedReleaseCount.sum(),
                    calculateAvgAcquireTime(),
                    maxAcquireTime.get(),
                    minAcquireTime.get() == Long.MAX_VALUE ? 0 : minAcquireTime.get(),
                    currentLockCount.get(),
                    peakLockCount.get(),
                    competitionCount.sum(),
                    highCompetitionCount.sum(),
                    calculateAvgWaitTime(),
                    maxWaitTime.get(),
                    concurrentContenders.get(),
                    peakConcurrentContenders.get()
            );
        } finally {
            statsLock.readLock().unlock();
        }
    }
    
    /**
     * 计算平均等待时间
     */
    private double calculateAvgWaitTime() {
        long competitionTotal = competitionCount.sum();
        return competitionTotal > 0 ? (double) totalWaitTime.get() / competitionTotal : 0;
    }

    /**
     * 计算平均获取时间
     */
    private double calculateAvgAcquireTime() {
        long successCount = successAcquireCount.sum();
        return successCount > 0 ? (double) totalAcquireTime.get() / successCount : 0;
    }

    /**
     * 重置统计信息
     */
    public void resetStats() {
        statsLock.writeLock().lock();
        try {
            // 重置基础统计
            totalAcquireCount.reset();
            successAcquireCount.reset();
            failedAcquireCount.reset();
            totalReleaseCount.reset();
            successReleaseCount.reset();
            failedReleaseCount.reset();
            totalAcquireTime.set(0);
            maxAcquireTime.set(0);
            minAcquireTime.set(Long.MAX_VALUE);
            currentLockCount.set(0);
            peakLockCount.set(0);
            
            // 重置竞争监控统计
            competitionCount.reset();
            highCompetitionCount.reset();
            totalWaitTime.set(0);
            maxWaitTime.set(0);
            concurrentContenders.set(0);
            peakConcurrentContenders.set(0);
        } finally {
            statsLock.writeLock().unlock();
        }
    }

    /**
     * 统计信息内部类
     */
    public static class StatsInfo {
        // 基础统计字段
        private final long totalAcquireCount;
        private final long successAcquireCount;
        private final long failedAcquireCount;
        private final long totalReleaseCount;
        private final long successReleaseCount;
        private final long failedReleaseCount;
        private final double avgAcquireTime;
        private final long maxAcquireTime;
        private final long minAcquireTime;
        private final long currentLockCount;
        private final long peakLockCount;
        
        // 竞争监控字段
        private final long competitionCount;
        private final long highCompetitionCount;
        private final double avgWaitTime;
        private final long maxWaitTime;
        private final int concurrentContenders;
        private final int peakConcurrentContenders;

        public StatsInfo(long totalAcquireCount, long successAcquireCount, long failedAcquireCount,
                        long totalReleaseCount, long successReleaseCount, long failedReleaseCount,
                        double avgAcquireTime, long maxAcquireTime, long minAcquireTime,
                        long currentLockCount, long peakLockCount,
                        long competitionCount, long highCompetitionCount,
                        double avgWaitTime, long maxWaitTime,
                        int concurrentContenders, int peakConcurrentContenders) {
            this.totalAcquireCount = totalAcquireCount;
            this.successAcquireCount = successAcquireCount;
            this.failedAcquireCount = failedAcquireCount;
            this.totalReleaseCount = totalReleaseCount;
            this.successReleaseCount = successReleaseCount;
            this.failedReleaseCount = failedReleaseCount;
            this.avgAcquireTime = avgAcquireTime;
            this.maxAcquireTime = maxAcquireTime;
            this.minAcquireTime = minAcquireTime;
            this.currentLockCount = currentLockCount;
            this.peakLockCount = peakLockCount;
            this.competitionCount = competitionCount;
            this.highCompetitionCount = highCompetitionCount;
            this.avgWaitTime = avgWaitTime;
            this.maxWaitTime = maxWaitTime;
            this.concurrentContenders = concurrentContenders;
            this.peakConcurrentContenders = peakConcurrentContenders;
        }

        @Override
        public String toString() {
            return String.format(
                    "Redis分布式锁统计信息：\n" +
                    "总尝试获取次数：%d\n" +
                    "成功获取次数：%d\n" +
                    "失败获取次数：%d\n" +
                    "获取成功率：%.2f%%\n" +
                    "总释放次数：%d\n" +
                    "成功释放次数：%d\n" +
                    "失败释放次数：%d\n" +
                    "平均获取时间：%.2fms\n" +
                    "最大获取时间：%dms\n" +
                    "最小获取时间：%dms\n" +
                    "当前持有锁数：%d\n" +
                    "峰值持有锁数：%d\n" +
                    "\n=== 锁竞争监控 ===\n" +
                    "竞争次数：%d\n" +
                    "高竞争次数（重试>3次）：%d\n" +
                    "高竞争比例：%.2f%%\n" +
                    "平均等待时间：%.2fms\n" +
                    "最大等待时间：%dms\n" +
                    "当前竞争线程数：%d\n" +
                    "峰值竞争线程数：%d",
                    totalAcquireCount,
                    successAcquireCount,
                    failedAcquireCount,
                    calculateSuccessRate(),
                    totalReleaseCount,
                    successReleaseCount,
                    failedReleaseCount,
                    avgAcquireTime,
                    maxAcquireTime,
                    minAcquireTime,
                    currentLockCount,
                    peakLockCount,
                    competitionCount,
                    highCompetitionCount,
                    calculateHighCompetitionRate(),
                    avgWaitTime,
                    maxWaitTime,
                    concurrentContenders,
                    peakConcurrentContenders
            );
        }

        private double calculateSuccessRate() {
            return totalAcquireCount > 0 ? (double) successAcquireCount / totalAcquireCount * 100 : 0;
        }
        
        private double calculateHighCompetitionRate() {
            return competitionCount > 0 ? (double) highCompetitionCount / competitionCount * 100 : 0;
        }
    }
}